package com.qf.program.service;

import cn.hutool.core.util.ZipUtil;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import cn.hutool.db.ds.DSFactory;
import com.qf.program.utils.http.HttpClientConfig;
import com.qf.program.utils.http.HttpClientUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.message.BasicNameValuePair;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.parser.Parser;
import org.jsoup.select.Elements;

import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Slf4j
public class PubmedXmlLocal {

    public static Map<Integer, Integer> ERRORSIZE = new ConcurrentHashMap<>();
    // 跳出循环的条件 如果当前id 次数超过3词获取失败则记录在里面
    public static Map<Integer, Integer> ERRORSIZEMORETHREE = new ConcurrentHashMap<>();

    public static Integer TrySize = 2;

    public static boolean isDo = false;

    public static boolean checkExist = false;

    public static Integer TrySizeIndex = 1;

    public static Integer trySize = 1;

    public static void main(String[] args) throws SQLException {

        //2023年5月12日14:28:50 进行优化,如果第一遍跑完还有-1 则进行重新跑 -1 -> 0 加入集合 如果多次都是 则停止运行
        String insert = TableConfig.PMXMLTABLEALLNEW;
        //是不是要检查本地有没有 有的话默认不插入
        Db use = Db.use();
        // 1-100000 100001-200000 200001-368000
        while (true) {
            List<Entity> list = use.query("SELECT * FROM xml_ids WHERE flag = 0 LIMIT 100");
//            List<Entity> list = use.query("SELECT * FROM xml_ids WHERE flag = 0 and ( id between 1 and 100000 ) LIMIT 100 ");
            if (list.size() == 0) {
                break;
            }
            if (isDo && ERRORSIZE.size() == 0) {
                if (ERRORSIZEMORETHREE.size() > 0) {
                    trySize++;
                    break;
                }

            }
            list.parallelStream().forEach(j -> {
                int jid = j.getInt("id");
                if (ERRORSIZEMORETHREE.containsKey(jid)) {
                    try {
                        ERRORSIZE.remove(jid);
                    } catch (Exception e) {

                    }
                    log.info("因为超过次数此id略过+" + jid);
                    return;
                }
                try {
                    isDo = (true);
                    String pmids = j.getStr("pmids");
                    Integer flag = 0;
                    String replace = pmids.replace("[", "").replace("]", "");
                    String res = "";
                    if (checkExist) {
                        res = checkIsDown(insert, use, replace);
                    }else {
                        res = replace;
                    }

                    if (StringUtils.isEmpty(res)) {
                        flag = 1;
                        log.info("本地存在 略过++");
                    } else {
//                        log.info("检查后需要下载的pmid++" + res);
                        HttpClientConfig config = new HttpClientConfig()
                                .setUrl("https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi")
                                .build();
                        config.getNvpsList().add(new BasicNameValuePair("db", "pubmed"));
                        config.getNvpsList().add(new BasicNameValuePair("retmode", "xml"));
                        config.getNvpsList().add(new BasicNameValuePair("id", res));
                        String body = HttpClientUtil.post(config);
                        try {
                            Document parse = Jsoup.parse(body, "", Parser.xmlParser());
                            Elements pubmedArticle = parse.select("PubmedArticleSet");
                            for (Element element : pubmedArticle) {
                                Elements children = element.children();
                                if (children.size() > 0) {
                                    flag = 1;
                                }
//                                    log.info("共获取到[" + children.size() + "]条数据，开始插入数据库……");
                                Integer oknum = 0;
                                for (Element child : children) {
                                    try {
                                        String pmid = child.select("PMID").first().text();
                                        String xml = new StringBuffer().append("<" + child.nodeName() + ">\n").append(child.html()).append("\n</" + child.nodeName() + ">").toString();
                                        Long time = System.currentTimeMillis();
                                        Entity ins = Entity.create(insert)
                                                .set("pmid", pmid)
                                                .set("content", ZipUtil.gzip(xml, "utf-8"))
                                                .set("lastupdate", time);
//                                        use.insert(ins);
                                        use.insertOrUpdate(ins, "pmid");
//                                        System.out.println("pmid++"+pmid);
                                        oknum++;
                                    } catch (Exception ex) {
//                                            ex.printStackTrace();
                                    }
                                }
                                log.info("插入数据完成，共插入[" + oknum + "]条数据");
                            }
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                    }
                    if (flag == 1) {
                        try {
                            use.execute("UPDATE xml_ids SET flag = ? WHERE id = ?", 1, jid);
                            try {
                                ERRORSIZE.remove(jid);
                            } catch (Exception e) {

                            }
                        } catch (SQLException throwables) {
                            throwables.printStackTrace();
                        }
                    } else {
                        try {
                            use.execute("UPDATE xml_ids SET flag = ? WHERE id = ?", -1, jid);
                            ERRORSIZE.compute(jid, (k, v) -> {
                                if (v == null) {
                                    v = 1;
                                } else {
                                    v = v + 1;
                                }
                                return v;
                            });
                            if (ERRORSIZE.get(jid) > TrySize) {
                                ERRORSIZEMORETHREE.put(jid, ERRORSIZE.get(jid));
                                ERRORSIZE.remove(jid);
                            }
                        } catch (SQLException throwables) {
                            throwables.printStackTrace();
                        }
                    }
                } catch (Exception ex) {
                    try {
                        use.execute("UPDATE xml_ids SET flag = ? WHERE id = ?", -1, jid);
                        ERRORSIZE.compute(jid, (k, v) -> {
                            if (v == null) {
                                v = 1;
                            } else {
                                v = v + 1;
                            }
                            return v;
                        });
                        if (ERRORSIZE.get(jid) > TrySize) {
                            ERRORSIZEMORETHREE.put(jid, ERRORSIZE.get(jid));
                            ERRORSIZE.remove(jid);
                        }
                    } catch (SQLException throwables) {
                        throwables.printStackTrace();
                    }
                    ex.printStackTrace();
                }
            });
        }
        if (ERRORSIZE.size() > 0) {
            log.info("重试次数+" + TrySizeIndex);
            TrySizeIndex++;
            use.execute("UPDATE xml_ids SET flag = 0 where flag = -1");
            List<Entity> list = use.query("SELECT * FROM xml_ids WHERE flag = 0 LIMIT 100");
//            List<Entity> list = use.query("SELECT * FROM xml_ids WHERE flag = 0 and ( id between 1 and 100000 ) LIMIT 100 ");
            if (list.size() > 0) {
                log.info("进行新的循环ERRORSIZE数量是+" + ERRORSIZE.size());
                PubmedXmlLocal.main(args);
            }
        }else {
            log.info("开始单线程重试");
            PubmedXmlLocalCheck.main(args);
        }


    }

    /**
     * 检查本地有没有下载如果没下载了 返回没下载的数量
     *
     * @param dbName 检查的数据库
     * @param use    db
     * @param ids    需要下载的ids
     */
    @SneakyThrows
    public static String checkIsDown(String dbName, Db use, String ids) {

        String select = "select pmid from " + dbName + " where pmid in (" + ids + " )";
        List<Entity> query = use.query(select);
        Set<String> isDown = query.stream().map(o -> o.getStr("pmid").trim()).collect(Collectors.toSet());
        Set<String> todown = Arrays.asList(ids.split(",")).stream().map(o -> o.trim()).collect(Collectors.toSet());
        todown.removeAll(isDown);
        String join = String.join(",", todown);

        return join;

    }
}
